package com.yanqu.road.server.manager.activity.hsisland;

import com.yanqu.road.dao.impl.activity.hsisland.HsIslandFloorDataDaoImpl;
import com.yanqu.road.dao.impl.activity.hsisland.HsIslandUnionDataDaoImpl;
import com.yanqu.road.entity.activity.hsisland.HsIslandPosition;
import com.yanqu.road.entity.activity.hsisland.HsIslandReward;
import com.yanqu.road.entity.activity.hsisland.config.HsIslandBoxConfig;
import com.yanqu.road.entity.activity.hsisland.config.HsIslandConfig;
import com.yanqu.road.entity.activity.hsisland.config.HsIslandIslandConfig;
import com.yanqu.road.entity.activity.hsisland.data.HsIslandBoxData;
import com.yanqu.road.entity.activity.hsisland.data.HsIslandEventData;
import com.yanqu.road.entity.activity.hsisland.data.HsIslandFloorData;
import com.yanqu.road.entity.activity.hsisland.data.HsIslandMonsterData;
import com.yanqu.road.entity.activity.hsisland.enums.*;
import com.yanqu.road.entity.log.cross.hsisland.LogCrossHsIslandOpenBox;
import com.yanqu.road.exception.BusinessException;
import com.yanqu.road.pb.activity.HsIslandProto;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.activity.hsisland.pb.CrossHsIslandActivityPb;
import com.yanqu.road.server.manager.log.CrossAutoLogMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

public class CrossHsIslandFloor {

    /**
     * 海域数据
     */
    private HsIslandFloorData floorData;

    /**
     * 岛屿MAP(LinkedHashMap)
     */
    private Map<Integer, CrossHsIslandIsland> islandMap;

    /**
     * 删除的岛屿列表
     */
    private List<CrossHsIslandIsland> delIslandList = new ArrayList<>();

    /**
     * 海域上的玩家MAP
     */
    private Map<Long, CrossHsIslandUser> userMap;

    /**
     * 构造方法
     * @param floorData
     * @param islandMap
     */
    public CrossHsIslandFloor(HsIslandFloorData floorData, Map<Integer, CrossHsIslandIsland> islandMap, Map<Long, CrossHsIslandUser> userMap) {
        this.floorData = floorData;
        this.islandMap = islandMap;
        this.userMap = userMap;
    }

    /**
     * 数据存储
     */
    public void save() {
        //海域数据存储
        HsIslandFloorDataDaoImpl floorDataDao = new HsIslandFloorDataDaoImpl();
        if (this.floorData.isInsertOption()) {
            floorDataDao.add(this.floorData);
        } else if (this.floorData.isUpdateOption()) {
            floorDataDao.update(this.floorData);
        }
        //岛屿数据存储
        for (CrossHsIslandIsland island : this.islandMap.values()) {
            island.save();
        }
        //移除的岛屿数据存储
        List<CrossHsIslandIsland> delIslandList;
        synchronized (this.delIslandList) {
            delIslandList = new ArrayList<>(this.delIslandList);
            this.delIslandList.clear();
        }
        for (CrossHsIslandIsland island : delIslandList) {
            island.save();
        }
    }

    /**
     * 获取配置
     * @return
     */
    public HsIslandConfig getConfig() {
        return CrossHsIslandActivityMgr.getConfig(this.floorData.getActivityId(), this.floorData.getGroupId());
    }

    /**
     * 获取海域数据
     * @return
     */
    public HsIslandFloorData getFloorData() {
        return this.floorData;
    }

    /**
     * 获取岛屿MAP
     * @return
     */
    public Map<Integer, CrossHsIslandIsland> getIslandMap() {
        return this.islandMap;
    }

    /**
     * 获取岛
     * @param islandId
     * @return
     */
    public CrossHsIslandIsland getIsland(int islandId) {
        return this.islandMap.get(islandId);
    }

    /**
     * 获取玩家MAP
     * @return
     */
    public Map<Long, CrossHsIslandUser> getUserMap() {
        return this.userMap;
    }

    /**
     * 获取玩家
     * @param userId
     * @return
     */
    public CrossHsIslandUser getUser(long userId) {
        return this.userMap.get(userId);
    }

    /**
     * 注入玩家
     * @param user
     */
    public void putUser(CrossHsIslandUser user) {
        this.userMap.put(user.getUserData().getUserId(), user);
        user.getUserData().setFloorId(this.floorData.getFloorId());
        //获取最小人数的岛屿
        CrossHsIslandIsland island = this.getMinUserNumIsland();
        int islandId = island.getIslandData().getIslandId();
        user.getUserData().setIslandId(islandId);
        //初始坐标
        HsIslandPosition position = this.getConfig().getIslandBornPosition(islandId);
        int x = position.getX();
        int y = position.getY();
        user.getUserData().setX(x);
        user.getUserData().setY(y);
        //同步下海域玩家，我的位置
        this.syncUserChangePosition(user);
    }

    /**
     * 移除玩家
     * @param user
     */
    public void removeUser(CrossHsIslandUser user) {
        this.userMap.remove(user.getUserData().getUserId());
        //判断当前海域是否没有玩家了，就移除岛屿数据
        if (this.userMap.isEmpty()) {
            CrossHsIslandActivity activity = CrossHsIslandActivityMgr.getActivity(this.floorData.getActivityId(), this.floorData.getGroupId());
            for (CrossHsIslandIsland island : this.islandMap.values()) {
                island.getIslandData().setDelFlag(HsIslandYnFlagEnum.YES.getType());
                this.delIslandList.add(island);

                for (HsIslandEventData eventData : island.getEventMap().values()) {
                    if (eventData.getFinishFlag() == HsIslandFinishFlagEnum.FINISH_YES.getType()) {
                        continue;
                    }
                    HsIslandMonsterData monsterData = eventData.getMonsterData();
                    if (monsterData != null) {
                        if (activity != null) {
                            activity.addNeedCleanBattleFieldId(monsterData.getBattleFieldId());
                        }
                    }
                }
            }
            this.islandMap = new LinkedHashMap<>();
        }
    }

    /**
     * 检测是否可通行
     * @param islandId
     * @param x
     * @param y
     * @throws BusinessException
     */
    public void checkPositionCanMove(int islandId, int x, int y) throws BusinessException {
        String position = x + "," + y;
        //获取岛屿
        CrossHsIslandIsland island = this.getIsland(islandId);
        if (island == null) {
            throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_ISLAND_NOT_FOUND);
        }
        //获取岛屿配置
        HsIslandIslandConfig islandConfig = this.getConfig().getIslandConfig(islandId);
        //获取坐标是否存在
        Integer positionType = islandConfig.getPositionType(position);
        if (positionType == null) {
            throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_POSITION_CONFIG_NOT_FOUND);
        }
        //判断地块是否可以停留
        boolean stayFlag = HsIslandLatticeTypeEnum.checkCanStay(positionType);
        if (!stayFlag) {
            throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_POSITION_NOT_STAY);
        }
        //判断地块事件是否完结
        boolean stayNotEventFlag = HsIslandLatticeTypeEnum.checkCanStayNotEvent(positionType);
        if (!stayNotEventFlag) {
            //判断事件是否完结
            boolean finishFlag = island.checkPositionFinish(x, y);
            if (!finishFlag) {
                //判断是否有事件
                HsIslandEventData event = island.getEvent(x, y);
                if (event == null) {
                    throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_POSITION_NOT_EVENT_NOT_STAY);
                }
            }
        }
        //判断上下左右是否联通。出生点不需要判断
        if (positionType != HsIslandLatticeTypeEnum.LATTICE_TYPE_BORN.getType()) {
            boolean canMoveFlag = island.checkPositionLink(x, y);
            if (!canMoveFlag) {
                throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_POSITION_NOT_LINK);
            }
        }
    }

    /**
     * 同步玩家位置变更
     * @param syncUser
     */
    public void syncUserChangePosition(CrossHsIslandUser syncUser) {
        HsIslandProto.HsIslandSyncUserPositionMsg.Builder builder = HsIslandProto.HsIslandSyncUserPositionMsg.newBuilder();
        builder.setFloorId(syncUser.getUserData().getFloorId());
        builder.setIslandId(syncUser.getUserData().getIslandId());
        builder.setUserData(CrossHsIslandActivityPb.buildHsIslandUserData(syncUser));
        Set<Long> syncUserSet = new HashSet<>(this.userMap.keySet());
        syncUserSet.remove(syncUser.getUserData().getUserId());//排除掉当前玩家
        MessageHelper.sendPacketToAll(Protocol.U_HS_ISLAND_SYNC_USER_POSITION, builder, syncUserSet);
    }

    /**
     * 同步格子数据变更（单个玩家）
     * @param userId
     * @param islandId
     * @param x
     * @param y
     */
    public void syncLaChangeForUser(long userId, int islandId, int x, int y) {
        HsIslandProto.HsIslandSyncLandLatticeDataMsg.Builder msg = HsIslandProto.HsIslandSyncLandLatticeDataMsg.newBuilder();
        msg.setFloorId(this.getFloorData().getFloorId());
        msg.setIslandId(islandId);
        CrossHsIslandIsland island = this.islandMap.get(islandId);
        int finishFlag = island.checkPositionFinish(x, y) ? HsIslandFinishFlagEnum.FINISH_YES.getType() : HsIslandFinishFlagEnum.FINISH_NOT.getType();
        HsIslandEventData eventData = island.getEvent(x, y);
        HsIslandPosition position = new HsIslandPosition(x, y);
        //宝箱比较特殊，已完结也要展示
        if (this.floorData.getBoxIslandId() == islandId && this.getBox(position.getKey()) != null) {
            HsIslandBoxData box = this.getBox(position.getKey());
            HsIslandProto.HsIslandLatticeData.Builder latticeData = CrossHsIslandActivityPb.buildHsIslandBoxLatticeData(position, this, box);
            msg.addLattices(latticeData);
        } else {
            HsIslandProto.HsIslandLatticeData.Builder latticeData = CrossHsIslandActivityPb.buildHsIslandLatticeData(position, finishFlag, eventData);
            msg.addLattices(latticeData);
        }
        MessageHelper.sendPacket(Protocol.U_HS_ISLAND_SYNC_LATTICE_DATA, msg, userId);
    }

    /**
     * 同步格子数据变更
     * @param island
     * @param events
     * @param opSync 是否处理自己的同步的地块（同步自己的事件，客户端默认不处理，该字段设置成true才处理）
     */
    public void syncLaChange(int island, List<HsIslandEventData> events, boolean opSync) {
        //同步
        HsIslandProto.HsIslandSyncLandLatticeDataMsg.Builder msg = HsIslandProto.HsIslandSyncLandLatticeDataMsg.newBuilder();
        msg.setFloorId(this.getFloorData().getFloorId());
        msg.setIslandId(island);
        msg.setOpSelf(opSync);
        for (HsIslandEventData eventData : events) {
            for (HsIslandPosition position : eventData.getPositions()) {
                HsIslandProto.HsIslandLatticeData.Builder latticeData = CrossHsIslandActivityPb.buildHsIslandLatticeData(position, eventData.getFinishFlag(), eventData);
                msg.addLattices(latticeData);
            }
        }
        MessageHelper.sendPacketToAll(Protocol.U_HS_ISLAND_SYNC_LATTICE_DATA, msg, this.userMap.keySet());
    }

    /**
     * 同步格子数据变更
     * @param island
     * @param event
     * @param opSync 是否处理自己的同步的地块（同步自己的事件，客户端默认不处理，该字段设置成true才处理）
     */
    public void syncLaChange(int island, HsIslandEventData event, boolean opSync) {
        List<HsIslandEventData> events = new ArrayList<>();
        events.add(event);
        this.syncLaChange(island, events, opSync);
    }

    /**
     * 获取非固定的可探索的格子数量（排除掉宝箱格子，4格子事件）
     * @return
     */
    public int getCanExploreLaNum(int islandId) {
        CrossHsIslandIsland island = this.islandMap.get(islandId);
        Map<String, HsIslandBoxData> boxDataMap = null;
        if (island.getIslandData().getIslandId() == this.floorData.getBoxIslandId()) {
            boxDataMap = this.floorData.getBoxDataMap();
        }
        return island.getCanExploreLaNum(boxDataMap);
    }

    /**
     * 注入宝箱发现人
     * @param userId
     */
    public void setBoxFindUser(long userId) {
        this.floorData.setBoxFindUserId(userId);
    }

    /**
     * 获取宝箱
     * @param x
     * @param y
     * @return
     */
    public HsIslandBoxData getBox(int x, int y) {
        return this.getBox(x + "_" + y);
    }

    /**
     * 获取宝箱
     * @param key
     * @return
     */
    public HsIslandBoxData getBox(String key) {
        return this.floorData.getBoxDataMap().get(key);
    }

    /**
     * 获取宝箱总数
     * @return
     */
    public int getBoxAllNum() {
        return this.floorData.getBoxDataMap().size();
    }

    /**
     * 已领取的宝箱数量
     * @return
     */
    public int getBoxReceivedNum() {
        //获取已领取次数
        int receivedNum = 0;
        for (HsIslandBoxData boxData : this.floorData.getBoxDataMap().values()) {
            if (boxData.getUserId() > 0) {
                receivedNum++;
            }
        }
        return receivedNum;
    }

    /**
     * 玩家总宝箱数量
     * @param userId
     * @return
     */
    public int getBoxUserAllNum(long userId) {
        //可领取次数
        int num = this.getConfig().HSISLAND_BOX_TIMES;
        //发现者可领取多领取x次
        if (userId == this.floorData.getBoxFindUserId()) {
            num += this.getConfig().HSISLAND_FOUND_BOX_FREE_TIMES;
        }
        return num;
    }

    /**
     * 玩家已领取的宝箱数量
     * @param userId
     * @return
     */
    public int getBoxUserReceivedNum(long userId) {
        //获取已领取次数
        int receivedNum = 0;
        for (HsIslandBoxData boxData : this.floorData.getBoxDataMap().values()) {
            if (boxData.getUserId() == userId) {
                receivedNum++;
            }
        }
        return receivedNum;
    }

    /**
     * 判断是否还可领取宝箱
     * @param userId
     * @return
     */
    public boolean checkCanReceiveBox(long userId) {
        //可领取次数
        int num = this.getBoxUserAllNum(userId);
        //获取领取次数
        int receivedNum = this.getBoxUserReceivedNum(userId);
        if (num > receivedNum) {
            return true;
        }
        return false;
    }

    /**
     * 开启宝箱
     * @param user
     * @param x
     * @param y
     * @param island
     * @return
     * @throws BusinessException
     */
    public synchronized HsIslandReward openBox(CrossHsIslandUser user, int x, int y, CrossHsIslandIsland island) throws BusinessException {
        HsIslandBoxData boxData = this.getBox(x, y);
        if (boxData == null) {
            throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_BOX_NOT_FOUND);
        }
        //判断宝箱是否被领取
        if (boxData.getUserId() > 0) {
            throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_BOX_RECEIVED);
        }
        //是否还有领取次数
        boolean canReceive = this.checkCanReceiveBox(user.getUserData().getUserId());
        if (!canReceive) {
            throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_BOX_USER_NOT_NUM);
        }
        //消耗体力,宝箱发现者不需要消耗体力
        int costEnergy = 0;
        if (user.getUserData().getUserId() != this.floorData.getBoxFindUserId()) {
            costEnergy = this.getConfig().HSISLAND_BOX_CONSUME_ENERGY;//读配置
            if (costEnergy > 0) {
                boolean reduceEnergyFlag = user.reduceEnergy(costEnergy, HsIslandLogEnergyTypeEnum.COST_OPEN_BOX);
                if (!reduceEnergyFlag) {
                    throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_ENERGY_NOT_ENOUGH);
                }
            }
        }
        //奖励
        HsIslandBoxConfig boxConfig = this.getConfig().getBoxConfig(boxData.getBoxId());
        Property reward = PropertyHelper.parseNewStringToProperty(boxConfig.getReward());
        boxData.setUserId(user.getUserData().getUserId());
        boxData.setReward(PropertyHelper.parsePropertyToString(reward));
        boxData.setTime(System.currentTimeMillis());
        this.floorData.setUpdateOption();
        //获取事件
        HsIslandEventData event = null;
        if (island != null) {
            event = island.getEvent(x, y);
            if (event != null) {
                //事件完结
                island.finishEvent(event);
                //同步地块数据变更
                this.syncLaChange(island.getIslandData().getIslandId(), event, true);
            }
        }
        //日志
        LogCrossHsIslandOpenBox log = new LogCrossHsIslandOpenBox(
                this.floorData.getActivityId(),
                this.floorData.getGroupId(),
                this.floorData.getUnionId(),
                user.getUserData().getUserId(),
                this.floorData.getFloorId(),
                costEnergy,
                boxData.getReward()
        );
        CrossAutoLogMgr.add(log);
        //返回
        return user.createReward(0, reward, null, event);
    }

    /**
     * 一键开启宝箱
     * @param user
     * @return
     * @throws BusinessException
     */
    public synchronized List<HsIslandReward> oneKeyOpenBox(CrossHsIslandUser user, CrossHsIslandUnion union) throws BusinessException {
        //剩余宝箱数量
        int residueNum = this.getBoxAllNum() - this.getBoxReceivedNum();
        if (residueNum <= 0) {
            throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_BOX_NOT_NUM);
        }
        //获取玩家领取宝箱次数
        int canOpenNum = this.getBoxUserAllNum(user.getUserData().getUserId()) - this.getBoxUserReceivedNum(user.getUserData().getUserId());
        if (canOpenNum <= 0) {
            throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_BOX_USER_NOT_NUM);
        }
        //判断体力是否足够
        if (user.getUserData().getUserId() != this.floorData.getBoxFindUserId()) {
            int costEnergy = this.getConfig().HSISLAND_BOX_CONSUME_ENERGY;//读配置
            boolean reduceEnergyFlag = user.checkEnergyEnough(costEnergy * canOpenNum);
            if (!reduceEnergyFlag) {
                throw BusinessException.newException(GameErrorCode.E_HS_ISLAND_ENERGY_NOT_ENOUGH);
            }
        }
        //获取岛屿
        CrossHsIslandIsland island = this.getIsland(this.floorData.getBoxIslandId());
        //获取可领取的宝箱
        List<HsIslandReward> list = new ArrayList<>();
        for (HsIslandBoxData boxData : this.floorData.getBoxDataMap().values()) {
            if (boxData.getUserId() <= 0) {
                try {
                    HsIslandReward reward = this.openBox(user, boxData.getX(), boxData.getY(), island);
                    list.add(reward);
                    if (list.size() >= canOpenNum) {
                        break;
                    }
                } catch (BusinessException e) {
                    CrossHsIslandActivityMgr.getLogger().info("海神岛-一键开启宝箱-失败：{}", e.getCode());
                }
            }
        }
        return list;
    }

    /**
     * 获取海神之心数量
     * @return
     */
    public int getKeyNum() {
        int keyNum = 0;
        for (CrossHsIslandIsland island : this.islandMap.values()) {
            keyNum += island.getIslandData().getKeyNum();
        }
        return keyNum;
    }

    /**
     * 获取海域默认岛屿
     * @return
     */
    public CrossHsIslandIsland getFloorDefaultIsland() {
        CrossHsIslandIsland defaultIsland = null;
        for (CrossHsIslandIsland island : this.getIslandMap().values()) {
            defaultIsland = island;
            break;
        }
        return defaultIsland;
    }

    /**
     * 获取最少人数的岛屿
     * @return
     */
    public CrossHsIslandIsland getMinUserNumIsland() {
        int minUserNum = Integer.MAX_VALUE;
        CrossHsIslandIsland minUserNumIsland = null;
        for (CrossHsIslandIsland island : this.getIslandMap().values()) {
            int islandUserNum = this.getIslandUserNum(island.getIslandData().getIslandId());
            if (islandUserNum < minUserNum) {
                minUserNum = islandUserNum;
                minUserNumIsland = island;
            }
        }
        if (minUserNumIsland == null) {
            return getFloorDefaultIsland();
        }
        return minUserNumIsland;
    }

    /**
     * 获取岛屿上的玩家数量
     * @param islandId
     * @return
     */
    public int getIslandUserNum(int islandId) {
        int islandUserNum = 0;
        for (CrossHsIslandUser user : this.userMap.values()) {
            if (user.getUserData().getIslandId() == islandId) {
                islandUserNum++;
            }
        }
        return islandUserNum;
    }

    /**
     * 获取海域探索进度，千分比
     * @return
     */
    public int getExploreProgress() {
        int floorAllEventNum = 0;
        int floorHasEventNum = 0;
        for (CrossHsIslandIsland island : this.islandMap.values()) {
            //总事件数量
            int allNum = island.getAllEventNum();
            floorAllEventNum += allNum;
            //探索过的事件数量
            int hasNum = island.getExploredEventNum();
            floorHasEventNum += hasNum;
        }
        return BigDecimal.valueOf(floorHasEventNum).divide(BigDecimal.valueOf(floorAllEventNum), 8, RoundingMode.UP).multiply(BigDecimal.valueOf(1000)).intValue();
    }

    /**
     * 跑马灯-收集到海神之心
     * @param keyNum
     */
    public void syncMarqueeKeyMsg(int keyNum) {
        HsIslandProto.HsIslandSyncMarqueeMsg.Builder msg = HsIslandProto.HsIslandSyncMarqueeMsg.newBuilder();
        msg.setType(HsIslandMarqueeTypeEnum.MARQUEE_KEY.getType());
        msg.setKeyNum(keyNum);
        msg.setFloorId(this.floorData.getFloorId());
        MessageHelper.sendPacketToAll(Protocol.U_HS_ISLAND_SYNC_MARQUEE, msg, this.userMap.keySet());
    }

    /**
     * 获取海域事件唯一ID
     * @return
     */
    public int getUnEventIdAndIncrement() {
        int unEventId = this.floorData.getMaxUnEventId().getAndIncrement();
        this.floorData.setUpdateOption();
        return unEventId;
    }
}
